package com.pkk.penguin.frame.know.java.interview.year2021.atguigu_20210226.synchronizedlockreentrantlock;

import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.LockSupport;
import java.util.concurrent.locks.ReentrantLock;
import lombok.SneakyThrows;

/**
 * 几种线程同步的重要了解
 *
 * @author peikunkun
 * @version V1.0
 * @date 2021-03-01 16:46
 **/
public class SynchronizedLockReentrantLock {

  static ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 2, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<>(),
      new ThreadPoolExecutor.AbortPolicy());


  static Object synchronizedObj = new Object();


  static Lock lock = new ReentrantLock();
  static Condition condition = lock.newCondition();


  public static void main(String[] args) throws InterruptedException {
    locksupport_park_unpark();
  }

  /**
   * LockSupport的park与unpark的使用
   *
   * @return void
   * @Param
   * @author peikunkun
   * @date 2021/3/2 0002 上午 9:48
   * @since
   */
  private static void locksupport_park_unpark() {
    System.out.println("此方法测试描述：【"
        + "1:park与unpark不需要同步锁"
        + "2.unpark会申请一个且多次申请最多一个的令牌(连续申请多次最多只能申请一个),park会消费一个令牌,如果有令牌则消费,没有则堵塞"
        + "{也就是说LockSupport的无论先唤醒后等待,还是先等待还是后唤醒都可以支持执行}"
        + "3.park会让许可（permit）变为零，unpark会让许可(permit)变为1,多次连续unpark,许可依然是1，不会累加】");

    final Thread thread = new Thread(new Runnable() {
      @SneakyThrows
      @Override
      public void run() {
        //等待三秒
        Thread.sleep(3000L);

        System.out.println(Thread.currentThread().getName() + "开始执行了");
        LockSupport.park();
        //会进行堵塞
        LockSupport.park();
        System.out.println(Thread.currentThread().getName() + "通知成功");
      }
    });
    thread.start();

    final Thread threadb = new Thread(new Runnable() {
      @Override
      public void run() {
        LockSupport.unpark(thread);
        LockSupport.unpark(thread);
        System.out.println(Thread.currentThread().getName() + "开始通知了");
      }
    });
    threadb.start();
  }

  /**
   * reentrant的锁的使用
   *
   * @return void
   * @Param
   * @author peikunkun
   * @date 2021/3/1 0001 下午 6:50
   * @since
   */
  private static void reentrantlock_await_signal() {
    System.out.println("此方法测试描述：【"
        + "1:await阻塞与signal必须伴随着lock否则都会抛出异常java.lang.IllegalMonitorStateException"
        + "2.必须先await然后再signal,否则先signal操作在await操作,await操作之后阻塞，没有signal唤醒了】");

    executor.execute(new Runnable() {
      @SneakyThrows
      @Override
      public void run() {
        Thread.sleep(3000);
        try {
          lock.lock();
          System.out.println(Thread.currentThread().getName() + "开始执行了");
          try {
            condition.await();
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
          System.out.println(Thread.currentThread().getName() + "通知成功");
        } finally {
          lock.unlock();
        }

      }
    });

    executor.execute(new Runnable() {
      @Override
      public void run() {
        try {
          lock.lock();
          System.out.println(Thread.currentThread().getName() + "开始通知了");
          condition.signal();
        } finally {
          lock.unlock();
        }
      }
    });

    //不在接受任务
    executor.shutdown();
  }

  /**
   * wait与notify
   *
   * @return void
   * @Param
   * @author peikunkun
   * @date 2021/3/1 0001 下午 5:02
   * @since
   */
  private static void synchronized_wait_notify() {
    System.out.println("欢迎使用单元测试方法【Administrator_24()_20210301165650】");
    System.out.println("此方法测试描述：【"
        + "1:wait阻塞与notify必须伴随着synchronized否则都会抛出异常java.lang.IllegalMonitorStateException"
        + "2.必须先wait然后再notify,否则先notify操作在wait操作,wait操作之后阻塞，没有notify唤醒了】");

    executor.execute(new Runnable() {
      @SneakyThrows
      @Override
      public void run() {
        Thread.sleep(3000);
        synchronized (synchronizedObj) {
          System.out.println(Thread.currentThread().getName() + "开始执行了");
          try {
            synchronizedObj.wait();
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
          System.out.println(Thread.currentThread().getName() + "通知成功");
        }

      }
    });

    executor.execute(new Runnable() {
      @Override
      public void run() {
        synchronized (synchronizedObj) {
          System.out.println(Thread.currentThread().getName() + "开始通知了");
          synchronizedObj.notify();
        }

      }
    });

    //不在接受任务
    executor.shutdown();
  }


}
